home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / varie / uae-0_64.lha / uae-0.6.4 / src / execlib.c < prev    next >
C/C++ Source or Header  |  1996-09-10  |  43KB  |  1,491 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   * exec.library emulation
  5.   *
  6.   * Copyright 1996 Bernd Schmidt
  7.   */
  8.  
  9. #undef USE_EXECLIB
  10.  
  11. #include "sysconfig.h"
  12. #include "sysdeps.h"
  13.  
  14. #include <assert.h>
  15. #include <signal.h>
  16. #ifdef USE_EXECLIB
  17. #include <setjmp.h>
  18. #endif
  19.  
  20. #include "config.h"
  21. #include "options.h"
  22. #include "memory.h"
  23. #include "custom.h"
  24. #include "newcpu.h"
  25. #include "xwin.h"
  26. #include "autoconf.h"
  27. #include "osemu.h"
  28.  
  29. static CPTR sysbase;
  30.  
  31. /*
  32.  * Exec list management
  33.  */
  34.  
  35. void EXEC_NewList(CPTR list)
  36. {
  37.     put_long(list, list + 4);
  38.     put_long(list + 4, 0);
  39.     put_long(list + 8, list);
  40. }
  41.  
  42. void EXEC_Insert(CPTR list, CPTR node, CPTR pred)
  43. {
  44.     CPTR succ;
  45.     if (pred == 0)
  46.     pred = list;
  47.     put_long(node, succ = get_long(pred));
  48.     put_long(pred, node);
  49.     put_long(succ + 4, node);
  50.     put_long(node + 4, pred);
  51. }
  52.  
  53. void EXEC_Enqueue(CPTR list, CPTR node)
  54. {
  55.     int pri = (BYTE)get_byte (node + 9);
  56.     CPTR lnode = get_long(list); /* lh_Head */
  57.     CPTR prev = 0, next;
  58.     
  59.     for (;(next = get_long(lnode)) != 0 && (BYTE)get_byte(lnode + 9) >= pri;) {
  60.     prev = lnode;
  61.     lnode = next;
  62.     }
  63.     EXEC_Insert(list, node, prev);
  64. }
  65.  
  66. void EXEC_Remove(CPTR node)
  67. {
  68.     CPTR pred = get_long(node + 4), succ = get_long(node);
  69.     put_long(pred, succ);
  70.     put_long(succ + 4, pred);
  71. }
  72.  
  73. ULONG EXEC_RemHead(CPTR list)
  74. {
  75.     CPTR head = get_long(list);
  76.     if (get_long(head) == 0)
  77.     return 0;
  78.     EXEC_Remove(head);
  79.     return head;
  80. }
  81.  
  82. ULONG EXEC_RemTail(CPTR list)
  83. {
  84.     CPTR tail = get_long(list + 8);
  85.     if (get_long(tail + 4) == 0)
  86.     return 0;
  87.     
  88.     EXEC_Remove(tail);
  89.     return tail;
  90. }
  91.  
  92. void EXEC_AddTail(CPTR list, CPTR node) 
  93. {
  94.     EXEC_Insert(list, node, get_long(list + 8)); 
  95. }
  96.  
  97. CPTR EXEC_FindName(CPTR start, char *name)
  98. {
  99.     CPTR node = start;
  100.     if (name == NULL)
  101.     return 0;
  102.     
  103.     for (;;) {
  104.     CPTR nnp;
  105.     char *nn;
  106.  
  107.     node = get_long(start);
  108.  
  109.     if (node == 0)
  110.         break;
  111.     nnp = get_long(node + 10);
  112.     if (nnp != 0 && (nn = get_real_address(nnp)) != NULL)
  113.         if (strcmp(nn, name) == 0)
  114.         return node;
  115.     start = node;
  116.     }
  117.     return 0;
  118. }
  119.  
  120. static ULONG execl_Enqueue(void) { EXEC_Enqueue(regs.a[0], regs.a[1]); return 0; }
  121. static ULONG execl_Insert(void) { EXEC_Insert(regs.a[0], regs.a[1], regs.a[2]); return 0; }
  122. static ULONG execl_AddHead(void) { EXEC_Insert(regs.a[0], regs.a[1], 0); return 0; }
  123. static ULONG execl_AddTail(void) { EXEC_Insert(regs.a[0], regs.a[1], get_long(regs.a[0] + 8)); return 0; }
  124. static ULONG execl_Remove(void) { EXEC_Remove(regs.a[1]); return 0; }
  125. static ULONG execl_RemHead(void) { return EXEC_RemHead(regs.a[0]); }
  126. static ULONG execl_RemTail(void) { return EXEC_RemTail(regs.a[0]); }
  127. static ULONG execl_FindName(void) { CPTR n = EXEC_FindName(regs.a[0], get_real_address(regs.a[1])); ZFLG = n == 0; return n; }
  128.  
  129. /*
  130.  * Miscellaneous
  131.  */
  132.  
  133. void EXEC_InitStruct(CPTR inittable, CPTR memory, unsigned long size)
  134. {
  135.     CPTR dptr = memory;
  136.     UBYTE *mem = get_real_address(memory);
  137.     if (memory == 0 || mem == NULL || !valid_address(memory, size)) {
  138.     fprintf(stderr, "Foo\n");
  139.     return;
  140.     }
  141.     memset(mem, 0, size);
  142.     fprintf(stderr, "InitStruct\n");
  143.     for (;;) {
  144.     UBYTE command;
  145.     int count, desttype, srcloc;
  146.     ULONG offset;
  147.  
  148.     /* Read commands from even bytes */
  149.     inittable = (inittable + 1) & ~1;
  150.  
  151.     command = get_byte(inittable);
  152.     if (command == 0)
  153.         break;
  154.     desttype = (command >> 6) & 3;
  155.     srcloc = (command >> 4) & 3;
  156.     count = (command & 15) + 1;
  157.  
  158.     if (desttype == 3) {
  159.         dptr = memory + (get_long(inittable) & 0xFFFFFF);
  160.         inittable += 4;
  161.     } else if (desttype == 2) {
  162.         dptr = memory + get_byte(inittable+1), inittable += 2;
  163.     } else 
  164.         inittable++;
  165.  
  166.     if (srcloc != 0)
  167.         inittable = (inittable + 1) & ~1;
  168.  
  169.     if (desttype != 1) {
  170.         for(; count > 0; count--) {
  171.         switch (srcloc) {
  172.          case 0: put_long(dptr, get_long(inittable)); dptr += 4; inittable += 4; break;
  173.          case 1: put_word(dptr, get_word(inittable)); dptr += 2; inittable += 2; break;
  174.          case 2: put_byte(dptr, get_byte(inittable)); dptr += 1; inittable += 1; break;
  175.         }
  176.         }
  177.     } else {
  178.         ULONG data;
  179.         switch (srcloc) {
  180.          case 0: data = get_byte(inittable); inittable += 1; break;
  181.          case 1: data = get_word(inittable); inittable += 2; break;
  182.          case 2: data = get_long(inittable); inittable += 4; break;
  183.          default: data = 0; /* Alert */ break;
  184.         }
  185.         for(; count > 0; count--) {
  186.         switch (srcloc) {
  187.          case 0: put_long(dptr, data); dptr += 4; break;
  188.          case 1: put_word(dptr, data); dptr += 2; break;
  189.          case 2: put_byte(dptr, data); dptr += 1; break;
  190.         }
  191.         }
  192.     }
  193.     }
  194. }
  195. /* The size parameter sometimes seems to contain garbage in the top 16 bit */
  196. static ULONG execl_InitStruct(void) { EXEC_InitStruct(regs.a[1], regs.a[2], regs.d[0] & 0xFFFF); return 0; }
  197.  
  198. /*
  199.  * Interrupts
  200.  * This is all very confusing. As I see things, the IntVects field of the
  201.  * ExecBase is set up as follows:
  202.  *   One interrupt may either be assigned an IntServer, or an IntHandler.
  203.  *   PORTS, COPER, VERTB EXTER and NMI are set up as Servers (at least that's
  204.  *   what the AutoDocs say), the others as IntHandlers.
  205.  *   An IntServer field has a pointer to an Exec list in the iv_Data field,
  206.  *   the list contains all the server Interrupt nodes in a nice chain. The
  207.  *   iv_Node field is zero. For an IntHandler, the iv_Node field contains a
  208.  *   pointer to the node that was passed in SetIntVector.
  209.  */
  210.  
  211. CPTR EXEC_SetIntVector(int number, CPTR interrupt)
  212. {
  213.     CPTR oldvec = get_long(sysbase + 84 + 12*number + 8);
  214.     if (interrupt == 0) {
  215.     put_long(sysbase + 84 + 12*number, 0);
  216.     put_long(sysbase + 84 + 12*number + 4, 0);
  217.     put_long(sysbase + 84 + 12*number + 8, 0);
  218.     } else {
  219.     put_long(sysbase + 84 + 12*number, get_long(interrupt + 14));
  220.     put_long(sysbase + 84 + 12*number + 4, get_long(interrupt + 18));
  221.     put_long(sysbase + 84 + 12*number + 8, interrupt);
  222.     }
  223.     return oldvec;
  224. }
  225.  
  226. void EXEC_RemIntServer(ULONG nr, CPTR interrupt)
  227. {
  228.     CPTR list = get_long(sysbase + 84 + nr*12);
  229.     
  230.     EXEC_Remove(interrupt);
  231.     /* Disable interrupt if necessary */
  232.     if (get_long(get_long(list)) == 0)
  233.     put_word(0xDFF09A, 1 << nr);
  234. }
  235.  
  236. void EXEC_AddIntServer(ULONG nr, CPTR interrupt)
  237. {
  238.     CPTR list = get_long(sysbase + 84 + nr*12);
  239.     int was_empty;
  240.  
  241.     /* Disable interrupt if necessary */
  242.     was_empty = get_long(get_long(list)) == 0;
  243.     
  244.     EXEC_Enqueue(list, interrupt);
  245.     if (was_empty)
  246.     put_word(0xDFF09A, 0x8000 | (1 << nr));
  247.     
  248. }
  249.  
  250. static ULONG execl_SetIntVector(void) { return EXEC_SetIntVector(regs.d[0], regs.a[1]); }
  251. static ULONG execl_AddIntServer(void) { EXEC_AddIntServer(regs.d[0] & 15, regs.a[1]); return 0; }
  252. static ULONG execl_RemIntServer(void) { EXEC_RemIntServer(regs.d[0] & 15, regs.a[1]); return 0; }
  253.  
  254. /*
  255.  * Memory functions
  256.  */
  257.  
  258. #define MEMF_PUBLIC 1
  259. #define MEMF_CHIP 2
  260. #define MEMF_FAST 4
  261. #define MEMF_LOCAL 256
  262. #define MEMF_24BITDMA 512
  263. #define MEMF_CLEAR (1<<16)
  264. #define MEMF_LARGEST (1<<17)
  265. #define MEMF_REVERSE (1<<18)
  266. #define MEMF_TOTAL (1<<19)
  267.  
  268. CPTR EXEC_Allocate(CPTR memheader, unsigned long size)
  269. {
  270.     CPTR chunk, chunkpp;
  271.     unsigned long avail;
  272.     
  273.     size = (size + 7) & ~7;
  274.     
  275.     if (size == 0 || size > get_long(memheader + 28))
  276.     return 0;
  277.     
  278.     for (chunk = get_long(chunkpp = memheader + 16); chunk != 0; chunkpp = chunk, chunk = get_long(chunk))
  279.     if ((avail = get_long(chunk + 4)) >= size) {
  280.         CPTR nextchunk = get_long(chunk);
  281.         if (avail-size == 0)
  282.         put_long(chunkpp, nextchunk);
  283.         else {
  284.         put_long(chunkpp, chunk + size);
  285.         put_long(chunk + size, nextchunk);
  286.         put_long(chunk + size + 4, avail - size);
  287.         }
  288.         put_long(memheader + 28, get_long(memheader + 28) - size);
  289.         return chunk;
  290.     }
  291.     return 0;
  292. }
  293.  
  294. void EXEC_Deallocate(CPTR memheader, CPTR addr, unsigned long size)
  295. {
  296.     CPTR chunk, chunkpp;
  297.     CPTR areaend;
  298.  
  299.     if (addr == 0)
  300.     return;
  301.  
  302.     size = (size + 7) & ~7;
  303.     areaend = addr + size;
  304.     
  305.     put_long(memheader + 28, get_long(memheader + 28) + size);
  306.     
  307.     for (chunk = get_long(chunkpp = memheader + 16); chunk != 0; chunkpp = chunk, chunk = get_long(chunk)) {
  308.     if (chunk + get_long(chunk + 4) == addr) {
  309.         /* Merge with this and go ahead so we can also merge with the next */
  310.         put_long(chunkpp, get_long(chunk));
  311.         addr = chunk; size += get_long(chunk + 4);
  312.         chunk = chunkpp;
  313.         continue;
  314.     }
  315.     if (areaend == chunk) {
  316.         /* Merge with previous */
  317.         put_long(chunkpp, addr);
  318.         put_long(addr, get_long(chunk));
  319.         put_long(addr + 4, get_long(chunk + 4) + size);
  320.         return;
  321.     }
  322.     if (chunk > addr)
  323.         break;
  324.     }
  325.     put_long(chunkpp, addr);
  326.     put_long(addr, chunk);
  327.     put_long(addr + 4, size);
  328. }
  329.  
  330. CPTR EXEC_AllocMem(unsigned long size, ULONG requirements)
  331. {
  332.     CPTR nextmh,  memheader = get_long(sysbase + 322);
  333.     ULONG attrs = requirements & (MEMF_PUBLIC | MEMF_CHIP | MEMF_FAST);
  334.     CPTR result = 0;
  335.  
  336.     size = (size + 7) & ~7;
  337.  
  338.     for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
  339.     if ((get_word(memheader + 14) & attrs) != attrs)
  340.         continue;
  341.     result = EXEC_Allocate(memheader, size);
  342.     if (result != 0)
  343.         break;
  344.     }
  345.     if (result) {
  346.     if (requirements & MEMF_CLEAR)
  347.         memset(get_real_address(result), 0, size);
  348.     }
  349.     return result;
  350. }
  351.  
  352. CPTR EXEC_AllocEntry(CPTR ml)
  353. {
  354.     CPTR newml = EXEC_AllocMem(16 + 8*get_word(ml + 14), MEMF_PUBLIC|MEMF_CLEAR);
  355.     int i;
  356.  
  357.     if (newml == 0)
  358.     return 0x80000000|MEMF_PUBLIC;
  359.     for (i = 0; i < get_word(ml + 14); i++) {
  360.     ULONG reqs = get_long(ml + 16 + 8*i);
  361.     ULONG addr = EXEC_AllocMem(get_long(ml + 16 + 8*i + 4), reqs);
  362.     if (addr == 0)
  363.         /* Thank god for SetPatch */
  364.         return 0x80000000 | reqs;
  365.     put_long(newml + 16 + 8*i, addr);
  366.     put_long(newml + 16 + 8*i + 4, reqs);
  367.     }
  368.     return newml;
  369. }
  370.  
  371. void EXEC_FreeMem(CPTR addr, unsigned long size)
  372. {
  373.     CPTR nextmh,  memheader = get_long(sysbase + 322);
  374.  
  375.     size = (size + 7) & ~7;
  376.     if (addr == 0)
  377.     return;
  378.  
  379.     for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
  380.     if (get_long(memheader + 20) <= addr
  381.         && get_long(memheader + 24) > addr) {
  382.         EXEC_Deallocate(memheader, addr, size);
  383.         return;
  384.     }
  385.     }
  386. }
  387.  
  388. unsigned long EXEC_AvailMem(ULONG requirements)
  389. {
  390.     ULONG attrs = requirements & (MEMF_PUBLIC | MEMF_CHIP | MEMF_FAST);
  391.     CPTR nextmh, memheader = get_long(sysbase + 322);
  392.     CPTR result = 0;
  393.  
  394.     for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
  395.     if ((get_word(memheader + 14) & attrs) != attrs)
  396.         continue;
  397.     if (attrs & MEMF_LARGEST) {
  398.         unsigned long maxsize = 0;
  399.         CPTR chunk;
  400.         for (chunk = get_long(memheader + 16); chunk != 0; chunk = get_long(chunk))
  401.         if (get_long(chunk+4) > maxsize)
  402.             maxsize = get_long(chunk + 4);
  403.         result += maxsize;
  404.     } else if (attrs & MEMF_TOTAL) {
  405.         result += get_long(memheader + 24) - get_long(memheader + 20);
  406.     } else result += get_long(memheader + 28);
  407.     }
  408.     return result;
  409. }
  410.  
  411. void EXEC_AddMemList(unsigned long size, ULONG attrs, int pri, CPTR base,
  412.              CPTR name)
  413. {
  414.     put_byte(base + 8, 0);
  415.     put_byte(base + 9, pri);
  416.     put_long(base + 10, name);
  417.     put_word(base + 14, attrs);
  418.     put_long(base + 16, base + 32);
  419.     put_long(base + 20, base + 32);
  420.     put_long(base + 36, size - 32);
  421.     put_long(base + 28, size - 32);
  422.     put_long(base + 24, base + size);
  423.     EXEC_Enqueue(sysbase + 322, base);
  424. }
  425.  
  426. static ULONG execl_AddMemList(void)
  427. {
  428.     EXEC_AddMemList(regs.d[0], regs.d[1], (LONG)regs.d[2], regs.a[0], regs.a[1]);
  429.     return 0;
  430. }
  431.  
  432. static ULONG execl_CopyMem(void)
  433. {
  434.     UBYTE *src = get_real_address(regs.a[0]);
  435.     UBYTE *dst = get_real_address(regs.a[1]);
  436.  
  437.     if (src != NULL && dst != NULL
  438.     && valid_address(regs.a[0], regs.d[0])
  439.     && valid_address(regs.a[1], regs.d[0]))
  440.     memcpy(dst, src, regs.d[0]);
  441.     else
  442.     fprintf(stderr, "CopyMem with bogus parameters\n");
  443.     return 0;
  444. }
  445.  
  446. static ULONG execl_AllocMem(void) { return EXEC_AllocMem(regs.d[0], regs.d[1]); }
  447. static ULONG execl_AllocEntry(void) { return EXEC_AllocEntry(regs.a[0]); }
  448. static ULONG execl_Allocate(void) { return EXEC_Allocate(regs.a[0], regs.d[0]); }
  449. static ULONG execl_FreeMem(void) { EXEC_FreeMem(regs.a[1], regs.d[0]); return 0; }
  450. static ULONG execl_AvailMem(void) { return EXEC_AvailMem(regs.d[1]); }
  451. static ULONG execl_Deallocate(void) { EXEC_Deallocate(regs.a[0], regs.a[1], regs.d[0]); return 0; }
  452.  
  453. /*
  454.  * Scheduling
  455.  */
  456.  
  457. #define TS_RUN 2
  458. #define TS_READY 3
  459. #define TS_WAIT 4
  460. #define TS_EXCEPT 5
  461.  
  462. struct NewTask {
  463.     struct NewTask *next, *prev;
  464.     CPTR exectask;
  465. #ifdef USE_EXECLIB
  466.     jmp_buf j;
  467. #endif
  468.     void *stack;
  469.     struct regstruct regs;
  470.     struct flag_struct flags;
  471. };
  472.  
  473. static struct NewTask idle_task;
  474. static int intr_count, need_resched;
  475.  
  476. static struct NewTask *find_newtask(CPTR task)
  477. {
  478.     /* Ugh, this is ugly */
  479.     struct NewTask *t = &idle_task;
  480.     do {
  481.     if (t->exectask == task)
  482.         return t;
  483.     t = t->next;
  484.     } while (t != &idle_task);
  485.     fprintf(stderr, "Uh oh. Task list corrupt\n");
  486. }
  487.  
  488. static void schedule(void)
  489. {
  490. #ifdef USE_EXECLIB
  491.     CPTR readylist = sysbase + 406;
  492.     CPTR readytask = get_long(readylist);
  493.     CPTR runtask = get_long(sysbase + 276);
  494.     struct NewTask *runtask_nt, *readytask_nt;
  495.     unsigned long oldflags;
  496.  
  497.     int idis;
  498.     
  499.     need_resched = 0;
  500.     /* Any ready tasks? */
  501.     if (get_long(readytask) == 0)
  502.     return;
  503.     
  504.     /* If the running task is going to sleep, don't check priorities*/
  505.     if (get_byte(runtask + 15) != TS_WAIT) {
  506.     /* Has the running task a higher priority than any ready tasks? */
  507.     if ((BYTE)get_byte(runtask + 9) > (BYTE)get_byte(readytask + 9))
  508.     return;
  509.     /* We should only preempt a task of the same priority if the quantum
  510.      * has expired. Hmmm... */
  511.     }
  512.     if (get_byte(runtask + 15) == TS_RUN)
  513.     put_byte(runtask + 15, TS_READY);
  514.     if (get_byte(runtask + 15) == TS_WAIT)
  515.     EXEC_Enqueue(sysbase + 420, runtask);
  516.     else
  517.     EXEC_Enqueue(readylist, runtask);
  518.     put_byte(readytask + 15, TS_RUN);
  519.     EXEC_Remove(readytask);
  520.     
  521.     readytask_nt = find_newtask(readytask);
  522.     runtask_nt = find_newtask(runtask);
  523.     
  524.  
  525.     oldflags = regs.spcflags;
  526.     runtask_nt->regs = regs;
  527.     runtask_nt->flags = regflags;
  528.     regs = readytask_nt->regs;
  529.     regflags = readytask_nt->flags;
  530.     regs.spcflags = (regs.spcflags & ~PRESERVED_FLAGS) | (oldflags & PRESERVED_FLAGS);
  531.     
  532.     put_byte(runtask + 16, get_byte(sysbase + 294));
  533.     put_byte(runtask + 17, get_byte(sysbase + 295));
  534.     put_byte(sysbase + 294, idis = get_byte(readytask + 16));
  535.     put_byte(sysbase + 295, get_byte(readytask + 17));
  536.     put_long(sysbase + 276, readytask);
  537.     /* Set INTENA according to new interrupt enable status */
  538.     if (idis == 0xFF)
  539.     put_word(0xDFF09A, 0xC000);
  540.     else
  541.     put_word(0xDFF09A, 0x4000);
  542.     /* Whee... */
  543.     fprintf(stderr, "Task switch: new task %s\n", get_real_address(get_long(readytask + 10)));
  544.     if (setjmp(runtask_nt->j) == 0)
  545.     longjmp(readytask_nt->j, 1);
  546.     regs.spcflags &= ~SPCFLAG_BRK;
  547. #endif
  548. }
  549.  
  550. static __inline__ void maybe_schedule(void)
  551. {
  552.     /* @@@ Should we avoid a schedule when supervisor bit is set?
  553.      * Definitely not if the running task is the idle task */
  554.     if (intr_count == 0 && get_byte(sysbase + 294) == 0xFF && get_byte(sysbase + 295) == 0xFF && need_resched)
  555.     schedule();
  556. }
  557.  
  558. /*
  559.  * Signals
  560.  */
  561.  
  562. int EXEC_AllocSignal(int signum)
  563. {
  564.     CPTR thistask = get_long(sysbase + 276);
  565.     ULONG sigalloc = get_long(thistask + 18);
  566.     if (signum == -1)
  567.     for (signum = 0; signum < 32; signum++)
  568.         if ((sigalloc & (1 << signum)) == 0)
  569.         break;
  570.     
  571.     if ((sigalloc & (1 << signum)) == 0) {
  572.     put_long(thistask + 18, sigalloc | (1 << signum));
  573.     } else
  574.     signum = -1;
  575.  
  576.     return signum;
  577. }
  578.  
  579. void EXEC_FreeSignal(int signum)
  580. {
  581.     CPTR thistask = get_long(sysbase + 276);
  582.     if (signum != -1)
  583.     return;
  584.     put_long(thistask + 18, get_long(thistask + 18) & ~(1 << signum));
  585. }
  586.  
  587. ULONG EXEC_SetSignal(ULONG newsig, ULONG exec_sigmask)
  588. {
  589.     CPTR task = get_long(sysbase + 276);
  590.     ULONG signals = get_long(task + 26);
  591.     /* @@@ check SigExcept here */
  592.     put_long(task + 26, (signals & ~exec_sigmask) | (newsig & exec_sigmask));
  593.     return signals;
  594. }
  595.  
  596. void EXEC_Signal(CPTR task, ULONG exec_sigmask)
  597. {
  598.     ULONG exec_sigs = get_long(task + 26);
  599.     ULONG sigwait = get_long(task + 22);
  600.     put_long(task + 26, exec_sigs | exec_sigmask);
  601.     if (get_byte(task + 15) == TS_WAIT && (sigwait & exec_sigmask) != 0) {
  602.     EXEC_Remove(task);
  603.     EXEC_Enqueue(sysbase + 406, task);
  604.     need_resched = 1;
  605.     maybe_schedule();
  606.     }
  607. }
  608.  
  609. ULONG EXEC_Wait(ULONG exec_sigmask)
  610. {
  611.     CPTR task = get_long(sysbase + 276);
  612.     ULONG exec_sigs = get_long(task + 26);
  613.     if ((exec_sigs & exec_sigmask) != 0) {
  614.     put_long(task + 26, exec_sigs & ~exec_sigmask);
  615.     return exec_sigs & exec_sigmask;
  616.     }
  617.     if (get_byte(sysbase + 294) != 0xFF || get_byte(sysbase + 295) != 0xFF)
  618.     {
  619.     fprintf(stderr, "Arrgh, task Wait()ing when it shouldn't\n");
  620.     }
  621.     if (intr_count || regs.s) {
  622.     fprintf(stderr, "Arrgh, task Wait()ing when it _really_ shouldn't\n");
  623.     }
  624.  
  625.     put_byte(task + 15, TS_WAIT);
  626.     put_long(task + 22, exec_sigmask);
  627.     schedule();
  628.     exec_sigs = get_long(task + 26);
  629.     if ((exec_sigs & exec_sigmask) != 0) {
  630.     put_long(task + 26, exec_sigs & ~exec_sigmask);
  631.     return exec_sigs & exec_sigmask;
  632.     } 
  633.     fprintf(stderr, "Bug: task woke up without signals\n");
  634.     return 0;
  635. }
  636.  
  637. static ULONG execl_SetSignal(void) { return EXEC_SetSignal(regs.d[0], regs.d[1]); }
  638. static ULONG execl_Signal(void) { EXEC_Signal(regs.a[1], regs.d[0]); return 0; }
  639. static ULONG execl_Wait(void) { return EXEC_Wait(regs.d[0]); }
  640. static ULONG execl_AllocSignal(void) { return EXEC_AllocSignal((BYTE)regs.d[0]); }
  641. static ULONG execl_FreeSignal(void) { EXEC_FreeSignal((BYTE)regs.d[0]); return 0; }
  642.  
  643. /*
  644.  * Semaphores
  645.  */
  646.  
  647. void EXEC_InitSemaphore(CPTR exec_sigsem)
  648. {
  649.     EXEC_NewList(exec_sigsem + 16);
  650.     put_word(exec_sigsem + 14, 0);
  651.     put_word(exec_sigsem + 44, 0xFFFF);
  652. }
  653.  
  654. ULONG EXEC_AttemptSemaphore(CPTR exec_sigsem)
  655. {
  656.     CPTR task = get_long(sysbase + 276);
  657.     UWORD count = get_word(exec_sigsem + 44);
  658.     if (count == 0xFFFF) {
  659.     /* Semaphore free -> lock it */
  660.     put_word(exec_sigsem + 44, 0);
  661.     put_long(exec_sigsem + 40, task);
  662.     put_word(exec_sigsem + 14, 1);
  663.     return 1;
  664.     }
  665.     if (get_long(exec_sigsem + 40) == task) {
  666.     /* Locked by same task -> Increment NestCount */
  667.     put_word(exec_sigsem + 14, get_word(exec_sigsem + 14) + 1);
  668.     return 1;
  669.     }
  670.     return 0;
  671. }
  672.  
  673. void EXEC_ObtainSemaphore(CPTR exec_sigsem)
  674. {
  675.     CPTR task = get_long(sysbase + 276);
  676.     UWORD count = get_word(exec_sigsem + 44);
  677.     if (count == 0xFFFF) {
  678.     /* Semaphore free -> lock it */
  679.     put_word(exec_sigsem + 44, 0);
  680.     put_long(exec_sigsem + 40, task);
  681.     put_word(exec_sigsem + 14, 1);
  682.     return;
  683.     }
  684.     if (get_long(exec_sigsem + 40) == task) {
  685.     /* Locked by same task -> Increment NestCount */
  686.     put_word(exec_sigsem + 14, get_word(exec_sigsem + 14) + 1);
  687.     return;
  688.     }
  689.     /* Need to wait. */
  690.     /* @@@ None of the predefined signals in exec/tasks.h seem to be used
  691.      * for this. We use 0x8000, which appears not to be used otherwise */
  692.     put_word(exec_sigsem + 44, count + 1);
  693.     EXEC_AddTail(exec_sigsem + 16, task);
  694.     if (EXEC_Wait(0x8000) != 0x8000)
  695.     fprintf(stderr, "BUG\n");
  696.  
  697.     /* Now it's mine, all mine! */
  698.     put_long(exec_sigsem + 40, task);
  699.     put_word(exec_sigsem + 14, 1);
  700. }
  701.  
  702. void EXEC_ReleaseSemaphore(CPTR exec_sigsem)
  703. {
  704.     UWORD nest = get_word(exec_sigsem + 14);
  705.     put_word(exec_sigsem + 14, nest - 1);
  706.     if (nest == 1) {
  707.     /* We're losing it. Signal the first task on the wait queue
  708.      * (that one will in turn wake the next, etc.) */
  709.     CPTR task = EXEC_RemHead(exec_sigsem + 16);
  710.     UWORD count = get_word(exec_sigsem + 44);
  711.     put_word(exec_sigsem + 44, count - 1);
  712.     if (task) {
  713.         EXEC_Signal(task, 0x8000);
  714.     }
  715.     }
  716. }
  717.  
  718. static ULONG execl_ObtainSemaphore(void) { EXEC_ObtainSemaphore(regs.a[0]); return 0; }
  719. static ULONG execl_ReleaseSemaphore(void) { EXEC_ReleaseSemaphore(regs.a[0]); return 0; }
  720. static ULONG execl_FindSemaphore(void) { return EXEC_FindName(sysbase + 532, get_real_address(regs.a[1])); }
  721. static ULONG execl_InitSemaphore(void) { EXEC_InitSemaphore(regs.a[0]); return 0; }
  722. static ULONG execl_AttemptSemaphore(void) { return EXEC_AttemptSemaphore(regs.a[0]); }
  723. static ULONG execl_AddSemaphore(void) { put_byte(regs.a[1] + 8, 15); EXEC_Enqueue(sysbase + 532, regs.a[1]); return 0; }
  724.  
  725. /*
  726.  * Messages and ports
  727.  */
  728.  
  729. CPTR EXEC_GetMsg(CPTR port)
  730. {
  731.     return EXEC_RemHead(port + 20);
  732. }
  733.  
  734. /* This is shared between PutMsg and ReplyMsg */
  735. static void EXEC_doputmsg(CPTR port, CPTR msg)
  736. {
  737.     UBYTE flags = get_byte (port + 14);
  738.     EXEC_AddTail(port + 20, msg);
  739.     if (flags == 0)
  740.     EXEC_Signal(get_long(port + 16), 1 << get_byte(port + 15));
  741.     else if (flags == 1)
  742.     fprintf(stderr, "PA_SOFTINT unsupported\n");
  743.     
  744. }
  745.  
  746. void EXEC_PutMsg(CPTR port, CPTR msg)
  747. {
  748.     put_byte(msg + 8, 5);
  749.     EXEC_doputmsg(port, msg);
  750. }
  751.  
  752. void EXEC_ReplyMsg(CPTR msg)
  753. {    
  754.     put_byte(msg + 8, 7);
  755.     EXEC_doputmsg(get_long(msg + 14), msg);
  756. }
  757.  
  758. CPTR EXEC_WaitPort(CPTR port)
  759. {
  760.     for (;;) {
  761.     CPTR msg = get_long(port + 20);
  762.     if (get_long(msg) != 0)
  763.         return msg;
  764.     if (get_byte(port + 14) != 0)
  765.         fprintf(stderr, "Don't know how to WaitPort()\n");
  766.     EXEC_Wait(1 << get_byte(port + 15));
  767.     }
  768. }
  769.  
  770. static ULONG execl_GetMsg(void) { return EXEC_GetMsg(regs.a[0]); }
  771. static ULONG execl_PutMsg(void) { EXEC_PutMsg(regs.a[0], regs.a[1]); return 0; }
  772. static ULONG execl_ReplyMsg(void) { EXEC_ReplyMsg(regs.a[1]); return 0; }
  773. static ULONG execl_WaitPort(void) { return EXEC_WaitPort(regs.a[0]); }
  774. static ULONG execl_FindPort(void) { return EXEC_FindName(sysbase + 392, get_real_address(regs.a[1])); }
  775. static ULONG execl_AddPort(void) { put_byte(regs.a[1] + 8, 4); EXEC_Enqueue(sysbase + 392, regs.a[1]); return 0; }
  776.  
  777. /*
  778.  * I/O
  779.  */
  780.  
  781. LONG EXEC_WaitIO(CPTR ioreq)
  782. {
  783.     /* The device is supposed to clear the IO_QUICK bit if it's going to
  784.      * reply to the command */
  785.     if ((get_byte(ioreq + 30) & 1) == 1)
  786.     return (LONG)(BYTE)get_byte(ioreq + 31);
  787.  
  788.     for (;;) {
  789.     if (get_byte(ioreq + 8) == 7) /* NT_REPLYMSG? */
  790.         break;
  791.     /* We'll just hope that this a) has a ReplyPort and b) that port
  792.      * is of type PA_SIGNAL 
  793.      * Don't WaitPort() here: WaitPort() returns a message, and we
  794.      * aren't sure it's for us. */
  795.     
  796.     EXEC_Wait(1 << get_byte(get_long(ioreq + 14) + 15));
  797.     }
  798.     EXEC_Remove(ioreq);
  799.     return (LONG)(BYTE)get_byte(ioreq + 31);
  800. }
  801.  
  802. static void EXEC_BeginIO(CPTR ioreq)
  803. {
  804.     CPTR dev = get_long(ioreq + 20);
  805.     regs.a[6] = dev;
  806.     regs.a[1] = ioreq;
  807.     Call68k(dev - 30, 1);
  808. }
  809.  
  810. void EXEC_DoIO(CPTR ioreq)
  811. {
  812.     put_byte(ioreq + 30, 1);
  813.     EXEC_BeginIO(ioreq);
  814.     EXEC_WaitIO(ioreq);
  815. }
  816.     
  817. void EXEC_SendIO(CPTR ioreq)
  818. {
  819.     put_byte(ioreq + 30, 0);
  820.     EXEC_BeginIO(ioreq);
  821. }
  822.  
  823. CPTR EXEC_CheckIO(CPTR ioreq)
  824. {
  825.     if ((get_byte(ioreq + 30) & 1) == 1)
  826.     return ioreq;
  827.     if (get_byte(ioreq + 8) == 7)
  828.     return ioreq;
  829.     return 0;
  830. }
  831.  
  832. static ULONG execl_WaitIO(void) { return EXEC_WaitIO(regs.a[1]); }
  833. static ULONG execl_DoIO(void) { EXEC_DoIO(regs.a[1]); return 0;  }
  834. static ULONG execl_SendIO(void) { EXEC_SendIO(regs.a[1]); return 0;  }
  835. static ULONG execl_CheckIO(void) { return EXEC_CheckIO(regs.a[1]); }
  836.  
  837. /*
  838.  * Libraries
  839.  */
  840.  
  841. void EXEC_SumLibrary(CPTR lib)
  842. {
  843.     CPTR start = lib - get_word(lib + 16);
  844.     int len = get_word(lib + 16) + get_word(lib + 18);
  845.     ULONG sum = 0;
  846.     UWORD flags = get_word(lib + 14);
  847.     
  848.     if (flags & 1) /* SUMMING? */
  849.     return;
  850.     if (!(flags & 4)) /* SUMUSED? */
  851.     return;
  852.     put_word(lib + 14, flags & ~2); /* mark as not changed */
  853.     /* Pretend the checksum is OK, I don't care enough */
  854. }
  855.  
  856. CPTR EXEC_SetFunction(CPTR lib, int funcOffset, CPTR function)
  857. {
  858.     CPTR oldfunc = get_long(lib + funcOffset + 2);
  859.     put_word(lib + funcOffset, 0x4EF9);
  860.     put_long(lib + funcOffset + 2, function);
  861.     put_word(lib + 14, get_word(lib + 14) | 2);
  862.     EXEC_SumLibrary(lib);
  863.     return oldfunc;
  864. }
  865.  
  866. void EXEC_AddLibrary(CPTR lib)
  867. {
  868.     EXEC_Enqueue(sysbase + 378, lib);
  869.     put_word(lib + 14, 2); /* mark as changed */
  870.     EXEC_SumLibrary(lib);
  871. }
  872.  
  873. CPTR EXEC_OpenLibrary(char *name, int version)
  874. {
  875.     CPTR lib = EXEC_FindName(sysbase + 378, name);
  876.     if (lib != 0) {
  877.     regs.a[6] = lib;
  878.     regs.d[0] = version;
  879.     lib = Call68k(lib - 6, 1);
  880.     }
  881.     return lib;
  882. }
  883.  
  884. CPTR EXEC_OpenDevice(char *name, ULONG unit, CPTR ioRequest, ULONG flags)
  885. {
  886.     CPTR dev = EXEC_FindName(sysbase + 350, name);
  887.     CPTR replyport = get_long(ioRequest + 14);
  888.     put_long(ioRequest + 20, dev);
  889.     put_byte(ioRequest + 31, 0);
  890.     put_byte(ioRequest + 30, flags); /* is this right? */
  891.     if (replyport == 0)
  892.     fprintf(stderr, "ioRequest has no ReplyPort\n");
  893.     else {
  894.     CPTR rtask = get_long(replyport + 16);
  895.     if (rtask == 0)
  896.         fprintf(stderr, "replyTask == 0\n");
  897.     else if (rtask != get_long(sysbase + 276))
  898.         fprintf(stderr, "replyTask != current\n");
  899. /*    put_long(replyport + 16, get_long(sysbase + 276));*/
  900.     }
  901.     if (dev != 0) {
  902.     regs.a[6] = dev;
  903.     regs.a[1] = ioRequest;
  904.     regs.d[0] = unit;
  905.     regs.d[1] = flags;
  906.     dev = Call68k(dev - 6, 1);
  907.     }
  908.     return (LONG)(BYTE)get_byte(ioRequest + 31);
  909. }
  910.  
  911. void EXEC_AddDevice(CPTR lib)
  912. {
  913.     EXEC_Enqueue(sysbase + 350, lib);
  914. }
  915.  
  916. void EXEC_AddResource(CPTR lib)
  917. {
  918.     EXEC_Enqueue(sysbase + 336, lib);
  919. }
  920.  
  921. CPTR EXEC_OpenResource(char *name)
  922. {
  923.     CPTR lib = EXEC_FindName(sysbase + 336, name);
  924.     return lib;
  925. }
  926.  
  927. void EXEC_MakeFunctions(CPTR target, CPTR funcarray, CPTR funcdispb)
  928. {
  929.     if (funcdispb != 0) {
  930.     WORD tmp;
  931.     for (;;) {
  932.         tmp = get_word(funcarray); funcarray += 2;
  933.         if (tmp == -1)
  934.         break;
  935.         target -= 6;
  936.         put_word(target, 0x4EF9); /* JMP.L */
  937.         put_long(target + 2, funcdispb + tmp);
  938.     }
  939.     } else {
  940.     CPTR tmp;
  941.     for (;;) {
  942.         tmp = get_long(funcarray); funcarray += 4;
  943.         if (tmp == (CPTR)-1)
  944.         break;
  945.         target -= 6;
  946.         put_word(target, 0x4EF9); /* JMP.L */
  947.         put_long(target + 2, tmp);
  948.     }
  949.     }
  950. }
  951.  
  952. /* This doesn't work yet */
  953. CPTR EXEC_MakeLibrary(CPTR vectors, CPTR structure, CPTR init,
  954.               unsigned long dsize, ULONG seglist_b)
  955. {
  956.     CPTR seglist = seglist_b << 2;
  957.     int vec_cnt = 0;
  958.     unsigned long negsize;
  959.     CPTR base, fdispb = 0, funcarray = vectors;
  960.     ULONG retval = 0;
  961.  
  962.     fprintf(stderr, "MakeLibrary\n");
  963.     if (get_word (vectors) == (UWORD)-1) {
  964.     int offs = 2;
  965.     fdispb = vectors;
  966.     funcarray += 2;
  967.     while (get_word (vectors+offs) != (UWORD)-1) {
  968.         offs += 2;
  969.         vec_cnt++;
  970.     }
  971.     } else {
  972.     int offs = 0;
  973.     while (get_long (vectors+offs) != (LONG)-1) {
  974.         offs += 4; 
  975.         vec_cnt++;
  976.     }
  977.     }
  978.     negsize = (vec_cnt * 6 + 3) & ~3;
  979.     dsize = (dsize + 3) & ~3;
  980.  
  981.     base = EXEC_AllocMem(negsize + dsize, MEMF_PUBLIC|MEMF_CLEAR);
  982.     if (base == 0) /* Uh oh */
  983.     return 0;
  984.     EXEC_MakeFunctions(base + negsize, funcarray, fdispb);
  985.     base += negsize;
  986.     put_word(base + 16, negsize);
  987.     put_word(base + 18, dsize);
  988.     if (structure != 0) {
  989.     /* Size is set to 0 so we won't clear it again */
  990.     EXEC_InitStruct(structure, base, 0);
  991.     }
  992.     if (init != 0) {
  993.     regs.a[6] = sysbase;
  994.     regs.a[0] = seglist_b; /* BCPL seglist here? */
  995.     regs.d[0] = base;
  996.     /* call it */
  997.     retval = Call68k(init, 0);
  998.     } else
  999.     retval = base;
  1000.     
  1001.     return retval;
  1002. }
  1003.  
  1004. CPTR EXEC_InitResident(CPTR resident, ULONG segList)
  1005. {
  1006.     UBYTE flags = get_byte(resident + 10);
  1007.     
  1008.     if (flags & 0x80) {
  1009.     CPTR autoinit = get_long(resident + 22);
  1010.     return EXEC_MakeLibrary(get_long(autoinit + 4), get_long(autoinit + 8),
  1011.                 get_long(autoinit + 12), get_long(autoinit), segList >> 4);
  1012.     }
  1013.     
  1014.     regs.d[0] = 0; regs.a[0] = segList; regs.a[6] = sysbase;
  1015.     return Call68k(get_long(resident + 22), 0);
  1016. }
  1017.  
  1018. static ULONG execl_MakeFunctions(void) { EXEC_MakeFunctions(regs.a[0], regs.a[1], regs.a[2]); return 0; }
  1019. static ULONG execl_SumLibrary(void) { EXEC_SumLibrary(regs.a[1]); return 0; }
  1020. static ULONG execl_SetFunction(void) { return EXEC_SetFunction(regs.a[1], (WORD)regs.a[0], regs.d[0]); }
  1021. static ULONG execl_AddLibrary(void) { EXEC_AddLibrary(regs.a[1]); return 0; }
  1022. static ULONG execl_AddDevice(void) { EXEC_AddDevice(regs.a[1]); return 0; }
  1023. static ULONG execl_AddResource(void) { EXEC_AddResource(regs.a[1]); return 0; }
  1024. static ULONG execl_OpenLibrary(void) { return EXEC_OpenLibrary(get_real_address(regs.a[1]), regs.d[0]); }
  1025. static ULONG execl_OpenDevice(void) { return EXEC_OpenDevice(get_real_address(regs.a[0]), regs.d[0], regs.a[1], regs.d[1]); }
  1026. static ULONG execl_OpenResource(void) { return EXEC_OpenResource(get_real_address(regs.a[1])); }
  1027. static ULONG execl_MakeLibrary(void) { return EXEC_MakeLibrary(regs.a[0], regs.a[1], regs.a[2], regs.d[0], regs.d[1]); }
  1028.  
  1029. /*
  1030.  * Tasks
  1031.  */
  1032.  
  1033. static void task_startup(void)
  1034. {
  1035.     m68k_setpc(regs.pc);
  1036.     Call68k_retaddr(regs.pc, 0, get_long(regs.a[7] - 4));
  1037.     fprintf(stderr, "Task fell through at the end\n");
  1038. }
  1039.  
  1040. CPTR EXEC_AddTask(CPTR task, CPTR initPC, CPTR finalPC)
  1041. {
  1042. #ifdef USE_EXECLIB
  1043.     struct NewTask *nt = (struct NewTask *)malloc(sizeof (struct NewTask));
  1044.     nt->exectask = task;
  1045.     nt->prev = &idle_task;
  1046.     nt->next = idle_task.next;
  1047.     idle_task.next->prev = nt;
  1048.     idle_task.next = nt;
  1049.     memset(&nt->regs, 0, sizeof (nt->regs));
  1050.     nt->regs.pc = initPC;
  1051.     nt->regs.a[7] = get_long(task + 54);
  1052.  
  1053.     if (finalPC == 0)
  1054.     finalPC = 0xF0FFF0; /* standard "return from 68k mode" calltrap */
  1055.     put_byte(task + 16, 0xFF);
  1056.     put_byte(task + 17, 0xFF);
  1057.     put_long(nt->regs.a[7] - 4, finalPC);
  1058.     nt->stack = malloc(65536); /* @@@ make this smaller after checking that
  1059.                 * no parts of the emulator need much stack
  1060.                 * space */
  1061.     nt->j[0].__sp = nt->stack + 65536;
  1062.     nt->j[0].__pc = &task_startup;
  1063.     put_byte(task + 15, TS_READY);
  1064.     put_long(task + 18,0x0000FFFF); /* all tasks have the lower 16 signals allocated */
  1065.     EXEC_Enqueue(sysbase + 406, task);
  1066.     need_resched = 1;
  1067.     maybe_schedule();
  1068.     return task;
  1069. #endif
  1070. }
  1071.  
  1072. CPTR EXEC_FindTask(char *name)
  1073. {
  1074.     char *n;
  1075.     CPTR v;
  1076.  
  1077.     if (name == NULL || ((n = get_real_address(get_long(get_long(sysbase + 276) + 10))) != NULL
  1078.              && strcmp(n, name) == 0))
  1079.     return get_long(sysbase + 276);
  1080.     
  1081.     v = EXEC_FindName(sysbase + 406, name); /* ready tasks */
  1082.     if (v != 0)
  1083.     return v;
  1084.     return EXEC_FindName(sysbase + 420, name); /* waiting tasks */
  1085. }
  1086.  
  1087. static ULONG execl_FindTask(void) { return EXEC_FindTask(regs.a[1] == 0 ? NULL : get_real_address(regs.a[1])); }
  1088. static ULONG execl_AddTask(void) { return EXEC_AddTask(regs.a[1], regs.a[2], regs.a[3]); }
  1089.  
  1090. ULONG EXEC_Forbid(void)
  1091. {
  1092.     int count = (BYTE)get_byte(sysbase + 295);
  1093.     count++;
  1094.     put_byte(sysbase + 295, count);
  1095.     return 0; 
  1096. }
  1097. ULONG EXEC_Permit(void) 
  1098. {
  1099.     int count = (BYTE)get_byte(sysbase + 295);
  1100.     if (count == -1)
  1101.     fprintf(stderr, "Too many Permit() calls\n");
  1102.     else
  1103.     count--;
  1104.     put_byte(sysbase + 295, count);    
  1105.     maybe_schedule();
  1106.     return 0;
  1107. }
  1108.  
  1109. ULONG EXEC_Disable(void) 
  1110. {
  1111.     int count = (BYTE)get_byte(sysbase + 294);
  1112.     count++;
  1113.     put_byte(sysbase + 294, count);
  1114.     put_word(0xDFF09A, 0x4000);
  1115.     return 0;
  1116. }
  1117.  
  1118. ULONG EXEC_Enable(void)
  1119. {
  1120.     int count = (BYTE)get_byte(sysbase + 294);
  1121.     if (count == -1)
  1122.     fprintf(stderr, "Too many Enable() calls\n");
  1123.     else
  1124.     count--;
  1125.     if (count == -1)
  1126.     put_word(0xDFF09A, 0xC000);
  1127.     put_byte(sysbase + 294, count);
  1128.     maybe_schedule();
  1129.     return 0;
  1130. }
  1131. /*
  1132.  *  Initialization
  1133.  */
  1134. static ULONG execlib_init(void)
  1135. {
  1136.     sysbase = get_long(4);
  1137.     
  1138.     /* CopyMem and CopyMemQuick */
  1139.     libemu_InstallFunction(execl_CopyMem, sysbase, -630);
  1140.     libemu_InstallFunction(execl_CopyMem, sysbase, -624);
  1141.     libemu_InstallFunction(execl_Allocate, sysbase, -186);
  1142.     libemu_InstallFunction(execl_AllocMem, sysbase, -198);
  1143.     libemu_InstallFunction(execl_Deallocate, sysbase, -192);
  1144.     libemu_InstallFunction(execl_FreeMem, sysbase, -210);
  1145.     libemu_InstallFunction(execl_AvailMem, sysbase, -216);
  1146.     
  1147.     /* List management */
  1148.     libemu_InstallFunction(execl_Insert, sysbase, -234);
  1149.     libemu_InstallFunction(execl_AddHead, sysbase, -240);
  1150.     libemu_InstallFunction(execl_AddTail, sysbase, -246);
  1151.     libemu_InstallFunction(execl_Enqueue, sysbase, -270);
  1152.     libemu_InstallFunction(execl_RemHead, sysbase, -258);
  1153.     libemu_InstallFunction(execl_RemTail, sysbase, -264);
  1154.     libemu_InstallFunction(execl_Remove, sysbase, -252);
  1155.     libemu_InstallFunction(execl_FindName, sysbase, -276);
  1156.     
  1157.     /* Signals */
  1158.     libemu_InstallFunction(execl_AllocSignal, sysbase, -330);
  1159.     libemu_InstallFunction(execl_FreeSignal, sysbase, -336);
  1160.  
  1161.     /* Semaphores */
  1162.     libemu_InstallFunction(execl_FindSemaphore, sysbase, -594);
  1163.     libemu_InstallFunction(execl_InitSemaphore, sysbase, -558);
  1164.     libemu_InstallFunction(execl_AddSemaphore, sysbase, -600);
  1165.  
  1166.     /* Messages/Ports */
  1167.     libemu_InstallFunction(execl_FindPort, sysbase, -390);
  1168.     libemu_InstallFunction(execl_GetMsg, sysbase, -372);
  1169.  
  1170.     /* Libraries */
  1171.     libemu_InstallFunction(execl_MakeFunctions, sysbase, -90);
  1172.     libemu_InstallFunction(execl_SumLibrary, sysbase, -426);
  1173.     libemu_InstallFunction(execl_SetFunction, sysbase, -420);
  1174.     
  1175.     /* Tasks */
  1176.     libemu_InstallFunction(execl_FindTask, sysbase, -294);
  1177.  
  1178.     /* Interrupts */
  1179.     libemu_InstallFunction(execl_SetIntVector, sysbase, -162);
  1180.     libemu_InstallFunction(execl_AddIntServer, sysbase, -168);
  1181.     libemu_InstallFunction(execl_RemIntServer, sysbase, -174);
  1182.     
  1183.     /* Miscellaneous */
  1184.     libemu_InstallFunction(execl_InitStruct, sysbase, -78);
  1185.  
  1186.     return 0;
  1187. }
  1188.  
  1189. static ULONG execlib_init2(void)
  1190. {
  1191.     sysbase = get_long(4);
  1192.     
  1193.     libemu_InstallFunction(execl_AllocEntry, sysbase, -222);
  1194.     
  1195.     libemu_InstallFunction(execl_AddLibrary, sysbase, -396);
  1196.     libemu_InstallFunction(execl_AddDevice, sysbase, -432);
  1197.     libemu_InstallFunction(execl_AddResource, sysbase, -486);
  1198.     libemu_InstallFunction(execl_OpenLibrary, sysbase, -552);
  1199.     libemu_InstallFunction(execl_OpenDevice, sysbase, -444);
  1200.     libemu_InstallFunction(execl_OpenResource, sysbase, -498);
  1201.     libemu_InstallFunction(execl_MakeLibrary, sysbase, -84);
  1202.  
  1203.     libemu_InstallFunctionFlags(EXEC_Disable, sysbase, -120, TRAPFLAG_NORETVAL);
  1204.     libemu_InstallFunctionFlags(EXEC_Enable, sysbase, -126, TRAPFLAG_NORETVAL);
  1205.     libemu_InstallFunctionFlags(EXEC_Permit, sysbase, -138, TRAPFLAG_NORETVAL);
  1206.     libemu_InstallFunctionFlags(EXEC_Forbid, sysbase, -132, TRAPFLAG_NORETVAL);
  1207.     
  1208.     libemu_InstallFunction(execl_AddTask, sysbase, -282);
  1209.  
  1210.     libemu_InstallFunction(execl_SetSignal, sysbase, -306);
  1211.     libemu_InstallFunction(execl_Signal, sysbase, -324);
  1212.     libemu_InstallFunction(execl_Wait, sysbase, -318);
  1213.  
  1214.     libemu_InstallFunction(execl_PutMsg, sysbase, -366);
  1215.     libemu_InstallFunction(execl_ReplyMsg, sysbase, -378);
  1216.     libemu_InstallFunction(execl_WaitPort, sysbase, -384);
  1217.  
  1218.     libemu_InstallFunction(execl_WaitIO, sysbase, -474);
  1219.     libemu_InstallFunction(execl_DoIO, sysbase, -456);
  1220.     libemu_InstallFunction(execl_SendIO, sysbase, -462);
  1221.     libemu_InstallFunction(execl_CheckIO, sysbase, -468);
  1222.     
  1223.     libemu_InstallFunctionFlags(execl_ObtainSemaphore, sysbase, -564, TRAPFLAG_NORETVAL);
  1224.     libemu_InstallFunctionFlags(execl_ReleaseSemaphore, sysbase, -570, TRAPFLAG_NORETVAL);
  1225.     libemu_InstallFunction(execl_AttemptSemaphore, sysbase, -576);
  1226.  
  1227.     return 0;
  1228. }
  1229.  
  1230. /*
  1231.  * These functions are one day going to bootstrap the emulated Exec
  1232.  */
  1233.  
  1234. #define NR_EXEC_FUNCTIONS 105 /* V34 (1.3) maximum */
  1235.  
  1236. static ULONG EXEC_ENOSYS(void)
  1237. {
  1238.     fprintf(stderr, "Not a system call\n");
  1239.     return 0;
  1240. }
  1241.  
  1242. static ULONG EXEC_StandardIntVec(void)
  1243. {
  1244.     int num = regs.a[1];
  1245.     /* Call the IntHandlers */
  1246.     return 0;
  1247. }
  1248.  
  1249. static ULONG EXEC_IntTrap(void)
  1250. {
  1251.     UWORD intsreq = get_word(0xDFF01E) & get_word(0xDFF01C);
  1252.     int i;
  1253.     intr_count++;
  1254.     
  1255.     for (i = 13; i >= 0; i--) {
  1256.     if ((intsreq & (1 << i)) != 0) {
  1257.     /* Is this a server chain? */
  1258.         if (i == 3 || i == 4 || i == 5 || i == 13 || i == 15) {
  1259.         CPTR slist = get_long(sysbase + 84 + 12*i);
  1260.         CPTR snode = get_long(slist);
  1261.         for (;;) {
  1262.             if (get_long(snode) == 0)
  1263.             break;
  1264.             regs.a[0] = 0xDFF000;
  1265.             regs.a[5] = get_long(snode + 18);
  1266.             regs.a[1] = get_long(snode + 14);
  1267.             Call68k(regs.a[5], 0);
  1268.             if (ZFLG == 0)
  1269.             break;
  1270.             snode = get_long(snode);
  1271.         }
  1272.         put_word(0xDFF09C, 1 << i);
  1273.         } else {
  1274.         CPTR intnode = get_long(sysbase + 84 + 12*i + 8);
  1275.         regs.d[1] = intsreq;
  1276.         regs.a[1] = get_long(intnode + 14);
  1277.         regs.a[0] = 0xDFF000;
  1278.         regs.a[5] = get_long(intnode + 18);
  1279.         regs.a[6] = sysbase;
  1280.         Call68k(regs.a[5], 0);
  1281.         }
  1282.         break;
  1283.     }
  1284.     }
  1285.     if (i < 0)
  1286.     fprintf(stderr, "So what interrupt am I supposed to serve?\n");
  1287.     intr_count--;
  1288.     maybe_schedule();
  1289. }
  1290.  
  1291. void execlib_sysinit(void)
  1292. {
  1293.     CPTR tmp, tmp2;
  1294.     CPTR enosys = deftrap(EXEC_ENOSYS);
  1295.     CPTR intvec = deftrap(EXEC_StandardIntVec);
  1296.     CPTR inttrap = deftrap2(EXEC_IntTrap, TRAPFLAG_NORETVAL);
  1297.     CPTR sysstack;
  1298.     int i;
  1299.  
  1300.     tmp = here();
  1301.     calltrap2(enosys); dw(RTS);
  1302.     
  1303.     /* why 0x400? */
  1304.     sysbase = 0x400 + NR_EXEC_FUNCTIONS*6;
  1305.     memset(get_real_address(sysbase), 0, 558);
  1306.     put_long(4, sysbase);
  1307.  
  1308.     /* Build vectors. We initialize SetFunction so we can call execlib_Init() */
  1309.     tmp2 = here();
  1310.     calltrap(deftrap(execl_SetFunction));
  1311.     dw(RTS);
  1312.     for (i = 0; i < NR_EXEC_FUNCTIONS; i++) {
  1313.     put_word(sysbase - 6*(i+1), 0x4EF9);
  1314.     put_long(sysbase - 6*(i+1) + 2, i == 69 ? tmp2 : tmp);
  1315.     }
  1316.  
  1317.     /* Build syslists */
  1318.     EXEC_NewList(sysbase + 322); /* MemList */
  1319.     EXEC_NewList(sysbase + 336); /* ResourceList */
  1320.     EXEC_NewList(sysbase + 350); /* ResourceList */
  1321.     EXEC_NewList(sysbase + 364); /* List */
  1322.     EXEC_NewList(sysbase + 378); /* LibList */
  1323.     EXEC_NewList(sysbase + 392); /* PortList */
  1324.     EXEC_NewList(sysbase + 406); /* TaskReady */
  1325.     EXEC_NewList(sysbase + 420); /* TaskWait */
  1326.     EXEC_NewList(sysbase + 434); /* SoftInts[5] */
  1327.     EXEC_NewList(sysbase + 450); 
  1328.     EXEC_NewList(sysbase + 466); 
  1329.     EXEC_NewList(sysbase + 482); 
  1330.     EXEC_NewList(sysbase + 498); 
  1331.     EXEC_NewList(sysbase + 532); /* SemaphoreList */
  1332.  
  1333.     tmp = sysbase + 558; /* sizeof struct V34 execbase */
  1334.     /* We put the supervisor stack at the end, the user stack for our new
  1335.      * task at the end - 0x800, and build the ResModules array at the bottom
  1336.      * of the stack */
  1337.     sysstack = chipmem_size - 0x2000;
  1338.     
  1339.     /* Don't mess with Fast or Bogo for now, just set up Chip */
  1340.     EXEC_AddMemList(sysstack - tmp, MEMF_CHIP|MEMF_PUBLIC, -10, tmp, 
  1341.             ds("Chip Memory"));
  1342.  
  1343.     /* Set up the CPU */
  1344.     regs.usp = chipmem_size - 0x800;
  1345.     regs.isp = chipmem_size; /* What about MSP? */
  1346.     regs.a[7] = regs.usp;
  1347.     regs.s = 0; regs.m = 0;
  1348.     regs.vbr = 0;
  1349.     regs.t0 = regs.t1 = 0;
  1350.     regs.intmask = 0;
  1351.     put_word(0xDFF09A, 0x7FFF);
  1352.     put_word(0xDFF096, 0x7FFF);
  1353.     put_word(0xDFF09C, 0x7FFF);
  1354.     put_word(0xDFF09A, 0xC000);
  1355.     put_word(0xDFF096, 0xE100);
  1356.     /* Initialize our supported functions */
  1357.     execlib_init();
  1358.     execlib_init2();
  1359.     
  1360.     /* Initialize interrupts */
  1361.     intr_count = 0; 
  1362.     put_byte(sysbase + 294, 0xFF);
  1363.     put_byte(sysbase + 295, 0xFF);
  1364.  
  1365.     tmp = here();
  1366.     calltrap2(inttrap);
  1367.     dw(RTE);
  1368.     for (i = 0; i < 8; i++)
  1369.     put_long((24+i)*4, tmp);
  1370.     
  1371.     tmp = here();
  1372.     calltrap2(intvec); dw(RTS);
  1373.     for (i = 0; i < 16; i++) {
  1374.     tmp2 = 0;
  1375.     /* Is this a server chain? */
  1376.     if (i == 3 || i == 4 || i == 5 || i == 13 || i == 15)
  1377.         EXEC_NewList(tmp2 = EXEC_AllocMem(14, MEMF_PUBLIC));
  1378.     put_long(sysbase + 84 + i*12, tmp2);
  1379.     put_long(sysbase + 84 + i*12 + 4, tmp);
  1380.     put_long(sysbase + 84 + i*12 + 8, 0);
  1381.     }
  1382.     put_word(0xDFF09A, 0xAFC3); /* Enable everything but the server chains */
  1383.     /* Set up the init task.  We don't really set it up properly. */
  1384.     tmp = EXEC_AllocMem(92, MEMF_CLEAR);
  1385.     put_long(sysbase + 276, tmp);
  1386.     put_byte(tmp + 8, 1);
  1387.     put_byte(tmp + 9, -127);
  1388.     put_long(tmp + 10, ds("init"));
  1389.     put_byte(tmp + 16, 0xFF);
  1390.     put_byte(tmp + 17, 0xFF);
  1391.     put_long(tmp + 54, chipmem_size - 0x804);
  1392.     put_long(tmp + 58, chipmem_size - 0x1800);
  1393.     put_long(tmp + 62, chipmem_size - 0x800);
  1394.     put_byte(tmp + 15, TS_RUN);
  1395.     put_long(tmp + 18,0x0000FFFF);
  1396.     EXEC_NewList(tmp + 74);
  1397.     idle_task.next = idle_task.prev = &idle_task;
  1398.     idle_task.exectask = tmp;
  1399.     idle_task.stack = NULL; /* we have a stack for this one already */
  1400.  
  1401.     /* Set up an idle task */
  1402.     tmp2 = here();
  1403.     dw (0x4E72); dw(0x2000); dw (0x4eF9); dl (tmp2);
  1404.  
  1405.     tmp = EXEC_AllocMem(92, MEMF_CLEAR);
  1406.     put_byte(tmp + 8, 1);
  1407.     put_byte(tmp + 9, -128);
  1408.     put_long(tmp + 10, ds("idle"));
  1409.     put_long(tmp + 58, chipmem_size - 0x2000);
  1410.     put_long(tmp + 62, chipmem_size - 0x1800);
  1411.     put_long(tmp + 54, chipmem_size - 0x1804);
  1412.     EXEC_NewList(tmp + 74);
  1413.     EXEC_AddTask(tmp,  tmp2, 0); /* This won't start executing yet */
  1414.     find_newtask(tmp)->regs.s = 1;
  1415.  
  1416.  
  1417.     /* Grep Kickstart for resident modules */
  1418.     regs.a[7] -= 4;
  1419.     put_long(regs.a[7], 0);
  1420.     tmp2 = regs.a[7];
  1421.     for (tmp = 0xF80000; tmp < 0xFFFFFF; tmp += 2) {
  1422.     if (get_word(tmp) == 0x4AFC && get_long(tmp + 2) == tmp) {
  1423.         regs.a[7] -= 4; put_long(regs.a[7], tmp);
  1424.     }
  1425.     }
  1426.     put_long(sysbase + 300, regs.a[7]);
  1427.     /* Bubble me do */
  1428.     for (tmp = regs.a[7]; tmp < tmp2; tmp += 4) {
  1429.     CPTR tmp3;
  1430.     for (tmp3 = tmp2 - 4; tmp3 > tmp; tmp3 -= 4) {
  1431.         if ((BYTE)get_byte(get_long(tmp3) + 13) > (BYTE)get_byte(get_long(tmp3 - 4) + 13)) {
  1432.         CPTR tmp4 = get_long(tmp3);
  1433.         put_long(tmp3, get_long(tmp3 - 4));
  1434.         put_long(tmp3 - 4, tmp4);
  1435.         }
  1436.     }
  1437.     }
  1438.     
  1439.     /* Initialize them and watch everything blow up. */
  1440.     for (tmp = regs.a[7]; (tmp2 = get_long(tmp)) != 0; tmp += 4) {
  1441.     UBYTE flags = get_byte(tmp2 + 10);
  1442.     if (!(flags & 1)) /* RTF_COLDSTART? */
  1443.         continue;
  1444.     if (strncmp("alert", get_real_address(get_long(tmp2 + 18)), 5) == 0)
  1445.         /*continue*/;
  1446.     fprintf(stderr, "Initializing %s\n", get_real_address(get_long(tmp2 + 18)));
  1447.     EXEC_InitResident(tmp2, /* ? */ 0);
  1448.     }
  1449.     /* Idle task */
  1450.     for(;;) {
  1451.     Call68k(0xF0FFF0 - 4, 0);
  1452.     schedule();
  1453.     }
  1454. }
  1455.  
  1456. /* 
  1457.  *  Install the gfx-library-replacement 
  1458.  */
  1459. void execlib_install(void)
  1460. {
  1461.     ULONG begin, end, resname, resid;
  1462.     int i;
  1463.     
  1464.     if (!use_gfxlib)
  1465.     return;
  1466.     
  1467.     resname = ds("UAEexeclib.resource");
  1468.     resid = ds("UAE execlib 0.1");
  1469.  
  1470.     begin = here();
  1471.     dw(0x4AFC);             /* RTC_MATCHWORD */
  1472.     dl(begin);              /* our start address */
  1473.     dl(0);                  /* Continue scan here */
  1474.     dw(0x0101);             /* RTF_COLDSTART; Version 1 */
  1475.     dw(0x0805);             /* NT_RESOURCE; pri 5 */
  1476.     dl(resname);            /* name */
  1477.     dl(resid);              /* ID */
  1478.     dl(here() + 4);         /* Init area: directly after this */
  1479.  
  1480.     calltrap(deftrap(execlib_init)); dw(RTS);
  1481.  
  1482.     end = here();
  1483.     org(begin + 6);
  1484.     dl(end);
  1485.  
  1486.     org(end);
  1487.  
  1488.     intr_count = 1; /* So we don't try to schedule if we don't emulate
  1489.              * all of Exec */
  1490. }
  1491.